package com.example.logtest;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.*;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;

public class CuratorTest {

    private static final String NODE_PATH = "/example/node";
    private static RetryPolicy retryPolicy  = new ExponentialBackoffRetry(1000,3);
    private static CuratorFramework client = CuratorFrameworkFactory.builder()
            .connectString("127.0.0.1:2181")
            .sessionTimeoutMs(300000)
            .connectionTimeoutMs(500000)
            .retryPolicy(retryPolicy)
            .build();

    public static void main(String[] args) throws Exception{
        /**
         * 创建会话
         * */
        client.start();

        PathChildrenCache pcc = new PathChildrenCache(client,"/Korea",true);

        NodeCache nodeCache =  new NodeCache(client,NODE_PATH);

        // 创建节点路径，如果不存在的话
        if (client.checkExists().forPath(NODE_PATH) == null) {
            client.create().creatingParentsIfNeeded().forPath(NODE_PATH, "棒棒的".getBytes("UTF-8"));
        }
        // 添加监听器
        NodeCacheListener listener = () -> {
            byte[] data = nodeCache.getCurrentData().getData();
            System.out.println("Node data updated, new data: " + new String(data));
        };
        nodeCache.getListenable().addListener(listener);
        nodeCache.start(false);

        // 模拟节点数据变化
        client.setData().forPath(NODE_PATH, "new data".getBytes("UTF-8"));
        pcc.getListenable().addListener(new PathChildrenCacheListener() {
            @Override
            public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
                switch (event.getType()) {
                    case CHILD_ADDED:
                        System.out.println("新增节点："+ event.getData().getPath());
                        System.out.println("新增节点数据："+ event.getData());
                        break;
                    case CHILD_REMOVED:
                        System.out.println("删除节点："+ event.getData().getPath());
                        break;
                    case CHILD_UPDATED:
                        System.out.println("更新节点："+ event.getData().getPath());
                        System.out.println("更新节点数据："+ event.getData());
                        break;
                    case INITIALIZED:
                        System.out.println("初始化节点："+ event.getData().getPath());
                        break;
                    default:
                        break;
                    }
                }
        }
        );
        pcc.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE);
        /**
         * 同步创建节点
         * 注意：
         *      1.除非指明创建节点的类型,默认是持久节点
         *      2.ZooKeeper规定:所有非叶子节点都是持久节点,所以递归创建出来的节点,
         *          只有最后的数据节点才是指定类型的节点,其父节点是持久节点
         * */

        //创建一个初始内容为空的节点
        if(!exists(client,"/China")){
            client.create().forPath("/China");
        }
        //给china添加一个下级节点
      //  client.create().creatingParentsIfNeeded().forPath("/China/aa");

        Thread.sleep(2000);

        //创建一个初始内容为空的临时节点
        if(!exists(client,"/America")){
            client.create().withMode(CreateMode.EPHEMERAL).forPath("/America");
        }

     /*   //创建一个初始内容不为空的临时节点，可以实现递归创建
        client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL)
                .forPath("/Japan","xiaoriben".getBytes());*/

/*
        *//**
         *  异步创建节点
         *
         * 注意:如果自己指定了线程池,那么相应的操作就会在线程池中执行,如果没有指定,
         *   那么就会使用Zookeeper的EventThread线程对事件进行串行处理
         * *//*
        client.create().withMode(CreateMode.EPHEMERAL).inBackground(new BackgroundCallback() {
            public void processResult(CuratorFramework client, CuratorEvent event) throws Exception {
                System.out.println("当前线程：" + Thread.currentThread().getName() + ",code:"
                        + event.getResultCode() + ",type:" + event.getType());
            }
        },Executors.newFixedThreadPool(10)).forPath("/async-China");


        client.create().withMode(CreateMode.EPHEMERAL).inBackground(new BackgroundCallback() {
            public void processResult(CuratorFramework client, CuratorEvent event) throws Exception {
                System.out.println("当前线程：" + Thread.currentThread().getName() + ",code:"
                        + event.getResultCode() + ",type:" + event.getType());
            }
        }).forPath("/async-America");*/

        /**
         * 获取节点内容
         * */
        byte[] data = client.getData().forPath("/Korea");
        System.out.println(new String(data));
        //传入一个旧的stat变量,来存储服务端返回的最新的节点状态信息
        byte[] data2 = client.getData().storingStatIn(new Stat()).forPath("/Korea");
        System.out.println(new String(data2));

        /**
         * 更新数据
         * */
        Stat stat = client.setData().forPath("/Korea");
        client.setData().forPath("/Korea", "jinsanpangzi".getBytes());

        client.setData().forPath("/China", "wxtest".getBytes());
        client.setData().forPath(NODE_PATH, "wxtest111".getBytes());
        client.create().creatingParentsIfNeeded().forPath("/Korea/bb");
        Thread.sleep(2000);
        client.setData().forPath("/Korea/bb", "111".getBytes());

       /* *//**
         * 删除节点
         * *//*

        //删除一个节点,并递归删除其所有子节点
        //client.delete().deletingChildrenIfNeeded().forPath("/China/aa");
        //只能删除叶子节点
        client.delete().forPath("/China");
        //强制指定版本进行删除
        client.delete().forPath("/Korea");
        //注意:由于一些网络原因,上述的删除操作有可能失败,使用guaranteed(),
        // 如果删除失败,会记录下来,只要会话有效,就会不断的重试,直到删除成功为止
        client.delete().guaranteed().forPath("/America");*/


        Thread.sleep(Integer.MAX_VALUE);


    }
    public static boolean exists(CuratorFramework client, String path) throws Exception {
        Stat stat = client.checkExists().forPath(path);
        return stat == null ? false : true;
    }
}